﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

using alib.Concurrency;
using alib.Debugging;
using alib.Enumerable;
using alib.String;
using alib.Collections.ReadOnly;

namespace agree.Pmrs
{
	using xmrs = agree.mrs;
	using agree.semi;
#if PMRS
	public partial class PortableMrs : atomic_selfhost
	{
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 
		/// </summary>
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		struct _tfs_build_helper
		{
			PortableMrs pmrs;
			Tfs tfs;
			Dictionary<int, atomic_base> mark_to_var;
			FeatMgr ftm;
			MrsManager mrsm;
			bool[] ignore;

			public _tfs_build_helper(PortableMrs pmrs, Tfs tfs)
			{
				this.pmrs = pmrs;
				this.mrsm = pmrs.mrsm;
				this.mark_to_var = new Dictionary<int, atomic_base>();
				this.tfs = tfs;
				this.ftm = mrsm.ftm;
				this.ignore = mrsm.ignored_feat_map;

				TfsSlot ts_mrs = tfs.MrsSlot;
				if (!ts_mrs.IsValid)
					throw new Exception();

				if ((ts_mrs.Edge.FlagsId & Edge.Flag.EtmNonBareType) == 0)
					throw new Exception();

				pmrs.hook = MakeNode<hook>(ts_mrs[mrsm.ifeat_hook]);

				TfsSlot[] rge;
				TfsSlot ts;
				if ((ts = ts_mrs[mrsm.RelsPath]).IsValid)
				{
					rge = ts.ListSlots;
					for (int i = 0; i < rge.Length; i++)
						pmrs.rels.Add(MakeNode<relation>(rge[i]));
				}

				if ((ts = ts_mrs[mrsm.HconsPath]).IsValid)
				{
					rge = ts.ListSlots;
					for (int i = 0; i < rge.Length; i++)
						pmrs.hcons.Add(MakeNode<qeq>(rge[i]));
				}

				//if (mrsm.AgreeConfig.Mrs.IconsPath.GetSlot(ts_mrs, out ts))
				//{
				//	rge = tfs.GetListSlots(ts.ix1);
				//	for (int i = 0; i < rge.Length; i++)
				//		pmrs.icons.Add(MakeNode<qeq>(rge[i]));
				//}
			}

			public atomic_base GetFeatureValue(TfsSlot ts)
			{
				atomic_base a;
				int m = ts.out_mark;
				if (m != 0)
				{
					Edge e_below;
					if (tfs.TryGetEdge(ts.mrsm.ifeat_instloc, m, out e_below) && e_below.FlagsId < 0)
					{
						if (!mark_to_var.TryGetValue(e_below.Mark, out a))
						{
							a = MakeNode<atomic_base>(ts);
							mark_to_var.Add(e_below.Mark, a);
						}
					}
					else if (!mark_to_var.TryGetValue(m, out a))
						a = MakeNode<atomic_base>(ts);
					else
						return a;

					mark_to_var[m] = a;
				}
				else
					a = MakeNode<atomic_base>(ts);

				return a;
			}

			T MakeNode<T>(TfsSlot ts)
				where T : atomic_base
			{
				String s_type = ftm.tu.TypeNameOrStringValue(ts.FlagsId);

				if ((ts.FlagsId & Edge.Flag.EtmNonBareType) != 0)
				{
					complex cplx;
					if (typeof(T) == typeof(relation))
						cplx = new relation(pmrs, s_type);
					else if (typeof(T) == typeof(qeq))
						cplx = new qeq(pmrs, s_type);
					else if (typeof(T) == typeof(hook))
						cplx = new hook(pmrs, s_type);
#if DEPRECATED_VARIABLE_MAPPING
					else if ((cplx = mrsm.GetVariableType_new(ts.FlagsId, pmrs, s_type)) is H)
						return cplx as T;
					if (cplx == null)
						cplx = new complex(pmrs, new atomic_type(pmrs, s_type));
#else
					else
						cplx = new complex(pmrs, new atomic_type(pmrs, s_type));
#endif

					foreach (int i_feat in ftm.rgrgfix_by_type[(int)(ts.FlagsId & Edge.Flag.MultiIdMask)])
					{
						if (ignore[i_feat])
							continue;
						int ix1 = tfs.GetEdgeIndex(i_feat, ts.out_mark);
						if (ix1 <= 0)
							continue;
						TfsSlot nts = new TfsSlot(tfs, ix1);
						cplx.SetFeatureValue(ftm[i_feat].feature, GetFeatureValue(nts));
					}
					return cplx as T;
				}
				else if (ts.Edge.FlagsId.IsIntegerValue())
					return new atomic_int(pmrs, ts.Edge.FlagsId.GetIntegerValue()) as T;
				else if (ts.Edge.FlagsId.IsStringFamilyValue())
					return new atomic_string(pmrs, s_type) as T;
				else
					return new atomic_type(pmrs, s_type) as T;
			}
		};
	}
#endif
}